/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 */

import path from 'path';

import { hvigorCore, TaskDetails } from '@ohos/hvigor';
import {
  build,
  BuildType,
  DependentModuleInfoV2,
  ProjectConfigEvolution,
  ProjectConfigEvolutionBuilder,
  CompileInnerParam
} from '@ohos/hvigor-arkts-compose';
import { Level, levels } from 'log4js';

import { getCurrentProductName } from '../../../common/find-target-product.js';
import { BuildArtifactConst } from '../../../const/build-directory-const.js';
import { CommonConst } from '../../../const/common-const.js';
import { CodeType } from '../../../enum/code-type-enum.js';
import { mapStringToModuleTypeEnum } from '../../../enum/module-type-enum.js';
import { CodeModel } from '../../../model/code-source/code-model.js';
import { Dependency } from '../../../project/dependency/core/dependency-interface.js';
import { HarArkCompile } from '../../../tasks/har/har-ark-compile.js';
import { TargetTaskService } from '../../../tasks/service/target-task-service.js';
import { getAppInfoByProject } from '../../../utils/integrated-hsp-utils.js';
import { handleLogs, OhosLogger } from '../../../utils/log/ohos-logger.js';
import { EvolutionService } from '../../service/evolution-service.js';
import { ServiceLocator } from '../../service/service-locator.js';

let level: Level = levels.DEBUG;

/**
 * 编译arkTS 2.0源码
 *
 * @since 2025/1/24
 */
export abstract class AbstractGenerateDeclaration extends HarArkCompile {
  protected readonly codeModel: CodeModel | undefined;
  protected readonly evolutionService: EvolutionService;

  public logger: OhosLogger = OhosLogger.getLogger(AbstractGenerateDeclaration.name);

  constructor(taskService: TargetTaskService, taskDetails: TaskDetails) {
    super(taskService, CodeType.ETS, taskDetails);
    this.evolutionService = ServiceLocator.getEvolutionService();
  }

  protected async buildProjectConfigEvolutionBuilder(): Promise<ProjectConfigEvolutionBuilder> {
    const projectConfig: ProjectConfigEvolution = {
      plugins: {
        'ArkUI': this.sdkInfo.getArkUIPlugin(),
        'ArkUI-Memo' : this.sdkInfo.getArkUIMemoPlugin(),
      },
      compileFiles: [],
      buildMode: this.targetService.getBuildMode(),
      projectRootPath: this.projectModel.getProjectDir(),
      moduleRootPath: this.moduleModel.getModule().getNodeDir(),
      cachePath: path.resolve(this.getTaskTempDir(this.targetData),
        this.targetService.getBuildMode().toLowerCase()),
      loaderOutPath: path.resolve(this.pathInfo.getInterMediatesLoaderOutPath(), CodeType.ETS),
      compileSdkVersion: this.compileApiVersion,
      compatibleSdkVersion: this.compatibleApiVersion,
      aceModuleJsonPath: this.aceModuleJsonPath!,
      appResource: this.resourceTable!,
      rawFileResource: this.rawFileResource!,
      bundleName: (() => {
        const { bundleName } = getAppInfoByProject(this.projectModel);
        return bundleName;
      })(),
      useNormalizedOHMUrl: this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl ?? false,
      buildType: BuildType.BUILD,
      packageName: this.moduleName,
      buildSdkPath: this.sdkInfo.getDriverBuild(),
      sourceRoots: ['./'],
      moduleType: this.moduleModel.getModuleType(),
      moduleName: this.moduleName,
      dependentModuleList: [],
      hasMainModule: false,
      buildLoaderJson: path.resolve(this.pathInfo.getIntermediatesLoaderPath(), BuildArtifactConst.LOADER_JSON),
      integratedHsp: this.moduleModel.isHspModule() ? (this.targetService.getBuildOption().arkOptions?.integratedHsp ?? false) : false,
      allowEmptyBundleName: hvigorCore.getParameter().getProperty(CommonConst.EMPTY_BUNDLENAME) ?? false,
      declgenV2OutPath: this.pathInfo.getDeclgenV2OutPath(),
      externalApiPaths: this.evolutionService.getLoadExternalApiPaths(this.targetData.isHarmonyOS(), this.sdkInfo),
      deviceTypes: this.moduleModel.getDeviceTypes(),
      permissions: this.moduleModel.getPermission(),
    };

    const innerParam: CompileInnerParam = {
      level: this.logger.getLevel() as Level,
    };

    return {
      ...projectConfig,
      ...innerParam
    };
  }

  /**
   * 收集依赖的模块信息
   * @protected
   */
  protected collectDependentModuleList(dependency: Dependency): DependentModuleInfoV2[] {
    const dependentModuleList: DependentModuleInfoV2[] = [];
    if (dependency.isLocal()) {
      dependentModuleList.push(this.collectLocalModuleInfo(dependency));
      const moduleService = ServiceLocator.getModuleTaskService(dependency.getModuleName());
      moduleService?.getAllDependencies().forEach((deps) => {
        if (deps.isLocal()) {
          dependentModuleList.push(this.collectLocalModuleInfo(deps));
        } else {
          dependentModuleList.push(this.collectRemoteModuleInfo(deps));
        }
      });
    } else {
      dependentModuleList.push(this.collectRemoteModuleInfo(dependency));
      const dependsKeys = Object.keys(dependency.getDependencies());
      this.service?.getAllDependencies()
        .filter(d => dependsKeys.includes(d.getPackageName()))
        .forEach((dep) => {
          dependentModuleList.push(this.collectRemoteModuleInfo(dep));
        });
    }
    return dependentModuleList;
  }

  /**
   * 收集本地模块信息
   * @param dependency
   */
  collectLocalModuleInfo(dependency: Dependency): DependentModuleInfoV2 {
    const modulePathInfo = ServiceLocator.getModulePathInfoServiceByProductAndModule(getCurrentProductName(), dependency.getModuleName());
    return {
      language: ServiceLocator.getModuleLanuage(dependency.getModuleName()),
      packageName: dependency.getPackageName(),
      moduleType: mapStringToModuleTypeEnum(dependency.getDependencyType())!,
      moduleName: dependency.getModuleName(),
      modulePath: dependency.getDependencyRootPath(),
      entryFile: path.resolve(dependency.getDependencyRootPath(), dependency.getDependencyMainFileRelativePath() ?? BuildArtifactConst.DEFAULT_INDEX_ETS),
      declFilesPath: modulePathInfo?.getDeclFileInfoJsonPath(),
      declgenV1OutPath: modulePathInfo?.getDeclgenV1OutPath(),
      declgenV2OutPath: modulePathInfo?.getDeclgenV2OutPath(),
      declgenBridgeCodePath: modulePathInfo?.getDeclgenBridgeCodePath(),
      sourceRoots: ['./'],
      dependencies: Object.keys(dependency.getDependencies()),
    };
  }

  /**
   * 收集三方包的信息
   * @param dependency
   */
  collectRemoteModuleInfo(dependency: Dependency): DependentModuleInfoV2 {
    const projectPath = this.projectModel.getProject().getNodeDir();
    const packageName = dependency.getPackageName();
    return {
      language: ServiceLocator.getModuleLanuage(dependency.getModuleName()),
      packageName: dependency.getPackageName(),
      moduleType: mapStringToModuleTypeEnum(dependency.getDependencyType())!,
      moduleName: dependency.getModuleName(),
      modulePath: dependency.getDependencyRootPath(),
      entryFile: path.resolve(dependency.getDependencyRootPath(), dependency.getDependencyMainFileRelativePath() ?? BuildArtifactConst.DEFAULT_INDEX_ETS),
      declFilesPath: this.pathInfo.getRemoteDependencyDeclFileInfoJsonPath(projectPath, packageName),
      declgenV1OutPath: this.pathInfo.getRemoteDependencyDeclgenV1OutPath(projectPath, packageName),
      declgenV2OutPath: this.pathInfo.getRemoteDependencyDeclgenV2OutPath(projectPath, packageName),
      declgenBridgeCodePath: this.pathInfo.getRemoteDependencyDeclgenBridgeCodePath(projectPath, packageName),
      sourceRoots: ['./'],
      dependencies: Object.keys(dependency.getDependencies()),
    };
  }

  protected async runBuild(projectConfig: ProjectConfigEvolutionBuilder, log: OhosLogger) {
    level = levels.getLevel(projectConfig.level!, levels.INFO);
    log.setLevel(level);
    const result = await build(projectConfig);
    handleLogs(result.compileLogEvents, log, level);
    if (!result.isSuccess) {
      throw result.error;
    }
  }
}
